package libs;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

import models.forms.ConversationForm;
import play.Application;
import play.Configuration;
import play.GlobalSettings;
import play.Play;
import play.libs.F.Promise;
import play.mvc.Action;
import play.mvc.Http.Context;
import play.mvc.Http.Request;
import play.mvc.SimpleResult;
import business.ConversationBusiness;

import com.google.gson.Gson;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ConsumerCancelledException;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.ShutdownSignalException;

public class Global extends GlobalSettings {

	public static ConnectionFactory factory;
	public Channel channel;
	public Connection connection;
	public boolean isStop = true;
	private Gson gson = new Gson();

	private String RAB_USERNAME = "rab.username";
	private String RAB_PASSWORD = "rab.password";
	private String RAB_HOST = "rab.host";
	private String RAB_PORT = "rab.port";
	// private String RAB_QUEUENAME = "rab.queueName";
	private String RAB_EXCHANGENAME = "rab.exchangeName";
	private String RAB_ROUTINGKEY = "rab.routingKey";

	public void onStart(Application app) {
		isStop = false;
		registerMessageListener();
	}

	public void onStop(Application app) {
		isStop = true;
		unregisterMessageListener();
	}

	@SuppressWarnings({ "rawtypes" })
	@Override
	public Action onRequest(Request request, Method actionMethod) {
		List<String> arrPath = Arrays.asList("Application/login", "Application/signup");
		String actionPath = actionMethod.getDeclaringClass().getSimpleName() + "/" + actionMethod.getName();
		System.out.println("The path of controller ..." + actionPath);

		if (!arrPath.contains(actionPath)) {
			return new Action.Simple() {
				@Override
				public Promise<SimpleResult> call(Context ctx) throws Throwable {
					System.out.println(ctx.session().get("userId"));
					if (Validation.isEmpty(ctx.session().get("userId"))) {
						System.out.println("redirect to login!!!");
						return Promise.pure(redirect("/login"));
					}
					return delegate.call(ctx);
				}
			};
		}
		return super.onRequest(request, actionMethod);
	}

	private void registerMessageListener() {
		Configuration configuration = Play.application().configuration();
		if (Global.factory == null) {
			Global.factory = new ConnectionFactory();
			factory.setUsername(configuration.getString(RAB_USERNAME));
			factory.setPassword(configuration.getString(RAB_PASSWORD));
			factory.setHost(configuration.getString(RAB_HOST));
			factory.setPort(Integer.parseInt(configuration.getString(RAB_PORT)));
			factory.setVirtualHost("/");
		}

		MessageListener msgListener;
		try {
			connection = factory.newConnection();
			channel = connection.createChannel();
			String queueName = channel.queueDeclare().getQueue();
			// String queueName = configuration.getString(RAB_QUEUENAME);
			// channel.queueDeclare(queueName, true, false, false, null);
			channel.queueBind(queueName, configuration.getString(RAB_EXCHANGENAME),
					configuration.getString(RAB_ROUTINGKEY));

			final QueueingConsumer consumer = new QueueingConsumer(channel);
			channel.basicConsume(queueName, true, consumer);

			msgListener = new MessageListener(consumer);
			msgListener.start();

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void unregisterMessageListener() {
		if (factory != null) {
			if (connection != null && connection.isOpen()) {
				try {
					connection.close();
					connection = null;
				} catch (IOException e) {
					e.printStackTrace(System.out);
				}
			}
			factory = null;
		}
	}

	private class MessageListener extends Thread {

		private QueueingConsumer consumer;
		private ConversationBusiness conversationBusiness = new ConversationBusiness();

		public MessageListener(QueueingConsumer consumer) {
			this.consumer = consumer;
		}

		@Override
		public void run() {
			System.out.println(" [*] Waiting for messages....");
			while (!isStop) {
				try {
					QueueingConsumer.Delivery delivery = consumer.nextDelivery();
					String message = new String(delivery.getBody());
					ConversationForm conversation = parseMessage(message);
					if (conversation != null && !Validation.isEmpty(conversation.getContent())) {
						System.out.println("String: " + message);
						System.out.println("Message: " + conversation.getContent());
						if("chat".equals(conversation.getMessageType())){
							conversationBusiness.insert(conversation);;
						}
					}
					
				} catch (InterruptedException ex) {
					ex.printStackTrace(System.out);
					break;
				} catch (ShutdownSignalException ex) {
					ex.printStackTrace(System.out);
					break;
				} catch (ConsumerCancelledException ex) {
					ex.printStackTrace(System.out);
					break;
				} catch (Exception ex) {
					ex.printStackTrace(System.out);
					break;
				}
			}
		}

		private ConversationForm parseMessage(String msg) {
			return gson.fromJson(msg, ConversationForm.class);
		}
	}

}
